package com.ezandroid.library.network.http.params;

import android.text.TextUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Set;

/**
 * 简单的Multipart Entity.
 *
 * @author markmjw
 * @date 2014-04-25
 */
public class SimpleMultipartEntity {
    public static final String BOUNDARY = "7cd4a6d158c";
    public static final String MP_BOUNDARY = "--" + BOUNDARY;
    public static final String END_MP_BOUNDARY = "--" + BOUNDARY + "--";
    public static final String END_LINE = "\r\n";

    public static final String UTF_8 = "UTF-8";

    private static final String CONTENT_TYPE = "multipart/form-data; boundary=" + BOUNDARY;

    private ByteArrayOutputStream mContent = new ByteArrayOutputStream();

    public SimpleMultipartEntity() {
    }

    public void addPart(final String key, final String value) throws IOException {
        addPart(key, value, null);
    }

    public void addPart(final String key, final String value, final String charset) throws IOException {
        StringBuilder builder = new StringBuilder();

        builder.append(MP_BOUNDARY).append(END_LINE);
        builder.append("Content-Disposition: form-data; name=\"").append(key).append("\"").append(END_LINE);
        builder.append("Content-Type: text/plain; charset=").append(TextUtils.isEmpty(charset) ? UTF_8 : charset).append(END_LINE);
        builder.append("Content-Transfer-Encoding: 8bit").append(END_LINE).append(END_LINE);
        builder.append(encode(value)).append(END_LINE);
        builder.append(MP_BOUNDARY).append(END_LINE);

        mContent.write(getBytes(builder.toString()));
    }

    public void addPart(final String key, final File file) throws IOException {
        addPart(key, file, null);
    }

    public void addPart(final String key, final File file, final String contentType) throws IOException {
        mContent.write(getBytes(MP_BOUNDARY + END_LINE));
        mContent.write(getBytes("Content-Disposition: form-data; name=\"" + key +
                "\"; filename=\"" + encode(file.getName()) + "\"" + END_LINE));

        String type = contentType;
        if (TextUtils.isEmpty(type)) {
            type = MIMEType.getContentType(file);
        }

        mContent.write(getBytes("Content-Type: " + type + END_LINE));
        mContent.write(getBytes("Content-Transfer-Encoding: binary" + END_LINE + END_LINE));
        mContent.write(getBytes(file));
        mContent.write(getBytes(END_LINE));
        mContent.flush();
    }

    public void addEndBoundary() throws IOException {
        mContent.write(getBytes(END_MP_BOUNDARY + END_LINE + END_LINE));
    }

    public void addTextParts(Map<String, String> textParams) throws IOException {
        StringBuilder builder = new StringBuilder();

        Set<String> keySet = textParams.keySet();
        for (String name : keySet) {
            String value = textParams.get(name);
            builder.append(MP_BOUNDARY).append(END_LINE);
            builder.append("Content-Disposition: form-data; name=\"").append(name).append("\"")
                    .append(END_LINE).append(END_LINE);
            builder.append(encode(value)).append(END_LINE);
        }

        mContent.write(builder.toString().getBytes());
    }

    public void addFileParts(Map<String, File> fileParams) throws IOException {
        Set<String> keySet = fileParams.keySet();
        for (String name : keySet) {
            File value = fileParams.get(name);
            mContent.write(getBytes(MP_BOUNDARY + END_LINE));
            mContent.write(getBytes("Content-Disposition: form-data; name=\"" + name +
                    "\"; filename=\"" + encode(value.getName()) + "\"" + END_LINE));
            mContent.write(getBytes("Content-Type: " + MIMEType.getContentType(value) + END_LINE));
            mContent.write(getBytes(END_LINE));
            mContent.write(getBytes(value));
            mContent.write(getBytes(END_LINE));
        }
    }

    private byte[] getBytes(File file) throws IOException {
        FileInputStream in = new FileInputStream(file);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int n;
        while ((n = in.read(b)) != -1) {
            out.write(b, 0, n);
        }
        in.close();
        return out.toByteArray();
    }

    private byte[] getBytes(String str) {
        return str.getBytes();
    }

    private String encode(String value) throws UnsupportedEncodingException {
        return URLEncoder.encode(value, UTF_8);
    }

    public byte[] getContentByte() {
        return mContent.toByteArray();
    }

    public long getContentLength() {
        return mContent.toByteArray().length;
    }

    public String getContentType() {
        return CONTENT_TYPE;
    }
}
